package com.uxsino.simo.indicator.retractor;

import com.uxsino.commons.utils.config.PropElement;
import com.uxsino.reactorq.model.INDICATOR_TYPE;
import com.uxsino.simo.indicator.CompoundIndicator;
import com.uxsino.simo.indicator.IIndicatorField;
import com.uxsino.simo.indicator.Indicator;
import com.uxsino.simo.networkentity.EntityInfo;
import com.uxsino.simo.query.QueryContext;
import com.uxsino.simo.query.QueryTemplate;
import com.uxsino.simo.utils.ConfigLoadingContext;
import com.uxsino.simo.utils.ConfigPropLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

public class CompoundValueRetractor extends AbstractValueRetractor<Map<String, Object>>
    implements ICompoundValueRetractor {
    private static Logger logger = LoggerFactory.getLogger(CompoundValueRetractor.class);

    protected Map<String, IValueRetractor> fieldRetrievers;

    public CompoundValueRetractor() {
        super(INDICATOR_TYPE.COMPOUND);
        fieldRetrievers = new HashMap<String, IValueRetractor>();
    }

    @Override
    public Object doRetract(EntityInfo entity, QueryContext ctxt, QueryTemplate qt, Object obj) {
        HashMap<String, Object> values = new HashMap<String, Object>(fieldRetrievers.size());

        for (Map.Entry<String, IValueRetractor> entry : fieldRetrievers.entrySet()) {
            Object value = null;
            try {
                value = entry.getValue().retract(entity, ctxt, qt, obj);
            } catch (NumberFormatException e) {
                logger.error("error retracting field:{}", entry.getKey(), e);
            }
            values.put(entry.getKey(), value);
        }
        return values;
    }

    public void addFieldRetreiver(String fieldName, IValueRetractor retriever) {
        fieldRetrievers.put(fieldName, retriever);
    }

    @Override
    public boolean retractsField(String fieldName) {
        return fieldRetrievers.containsKey(fieldName);
    }

    protected void setFieldValue(Map<String, Object> indValue, String fieldName, String fieldValue) {
        indValue.put(fieldName, fieldValue);
    }

    @Override
    public void loadProp(Indicator ind, PropElement eRetractor, ConfigLoadingContext lctxt) {
        /*TODO 解析器不限定指标类型,后续需要调整对应规则 if (!(ind instanceof CompoundIndicator)) {
            lctxt.error(eRetractor.getSourceLocation(), "{} must be CompoundIndicator type", ind.name);
            throw new IllegalArgumentException("must be CompoundIndicator type: " + ind.name);
        }*/

        for (PropElement eFld : eRetractor.getElements("field")) {
            loadFieldRetractor(ind, eFld, lctxt);
        }
    }

    /**
     * Load retractor for a field of {@link Indicator} {@code ind} using info
     * contained in the {@code "field"} sub{@link PropElement} {@code eFld}
     * <br />
     * private helper, called by {@code loadRetracts()} to deal with two types
     * of {@link CompoundValueRetractors}.
     * 
     * @param ind
     * @param cvr
     * @param eRetractor
     * @param loader
     */
    protected void loadFieldRetractor(Indicator ind, PropElement eFld, ConfigLoadingContext lctxt) {
        ConfigPropLoader loader = new ConfigPropLoader(lctxt);
        IIndicatorField fld = ((CompoundIndicator) ind).getField(eFld.getProp("name"));

        if (fld == null) {
            lctxt.error(eFld.getSourceLocation(), "cannot find field named:{}", eFld.getProp("name"));
            return;
        }
        String fieldParserName = eFld.getProp("parser");

        IValueRetractor retractor = null;
        try {
            if ("regex".equals(fieldParserName)) {
                String regexPattern = eFld.getProp("pattern");
                retractor = ValueRetractorFactory.createValueRetractor("regex", fld.getFieldType().caseIndType());
                if (regexPattern != null) {
                    ((RegexValueRetractor) retractor).setPattern(regexPattern);
                }
            } else if (fieldParserName != null && fieldParserName.length() != 0) {
                lctxt.error(eFld.getSourceLocation(),
                    "parser type: " + fieldParserName + " is not allowed here. ignored.");
            } else {
                retractor = ValueRetractorFactory.createValueRetractor("", fld.getFieldType().caseIndType());
            }
            loader.loadProperties(retractor, eFld);
            addFieldRetreiver(fld.getName(), retractor);
        } catch (Exception e) {
            lctxt.error(eFld.getSourceLocation(), " error loading retract for field {}\n{}", fld.getName(), e);
        }
    }

    @Override
    public void addFieldExpr(String fieldName, EXPRTYPE exprType, String expr) {

    }

    @Override
    public void postRetract(EntityInfo entity, QueryContext ctxt, QueryTemplate qt, Object obj) {
    }

}
